package dragon.modules.system.menu.dao;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import dragon.core.cache.CacheManager;
import dragon.core.cache.Caches;
import dragon.core.db.DBUtil;
import dragon.core.db.DML;
import dragon.core.exception.ExceptionHandler;
import dragon.core.system.po.SysMenu;
import dragon.core.util.Reflect;
import dragon.modules.system.menu.vo.SysMenu2;
import ejp.Database;

/**
 * Menu
 */
public class MenuDaoImpl {

	/**
	 * 根据ID获取菜单对象
	 * 
	 * @param id
	 *            菜单ID
	 * @return
	 * @throws ExceptionHandler
	 */
	public SysMenu get(int id) throws ExceptionHandler {
		return DML.loadObject(SysMenu.class, "where id=?", id);
	}

	/**
	 * 根据ID获取菜单对象
	 * 
	 * @param db
	 *            数据库对象，保证一个事务中操作
	 * @param id
	 *            菜单ID
	 * @return
	 * @throws ExceptionHandler
	 */
	public SysMenu get(Database db, int id) throws ExceptionHandler {
		return DML.loadObject(db, SysMenu.class, "where id=?", id);
	}

	/**
	 * 移动节点，该表部分的父节点
	 * 
	 * @param id
	 *            待移动的部门ID
	 * @param target
	 *            目标父节点ID
	 * @throws ExceptionHandler
	 */
	public void changeParent(int id, int target) throws ExceptionHandler {

		// 目标节点
		SysMenu newParent = get(target);
		if (newParent == null) {
			newParent = new SysMenu();
			newParent.setId(0);
			newParent.setIdpath("/");
			newParent.setKind("1");
		}
		// 目标不能为菜单实例
		if (newParent.getKind().equals("0")) {
			return;
		}

		// 获取待移动的菜单
		SysMenu menu = get(id);

		Database db = DBUtil.getDatabase();
		DML.beginTransaction(db);
		DML.executeUpdate(db, "update " + SysMenu.tableName + " set pid=" + newParent.getId() + " where id=" + id);
		if (menu.getPid() == 0) {
			// 删除路径最后一个斜线，避免路径相加出现双斜线
			StringBuffer sb_idpath = new StringBuffer(newParent.getIdpath());
			newParent.setIdpath(sb_idpath.deleteCharAt(sb_idpath.lastIndexOf("/")).toString());
			DML.executeUpdate(db, "update " + SysMenu.tableName + " set idpath='" + newParent.getIdpath() + "'||idpath where id=" + id + " or idpath like '%/" + id + "/%'");
		} else {
			// 加载旧的父节点数据
			SysMenu oldParent = get(menu.getPid());
			DML.executeUpdate(db, "update " + SysMenu.tableName + " set idpath=replace(idpath,'" + oldParent.getIdpath() + "','" + newParent.getIdpath() + "') where id=" + id + " or idpath like '%/"
					+ id + "/%'");
			oldParent = null;
		}
		DML.endTransaction(db);
		db = null;

		newParent = null;
		menu = null;
	}

	
	private static List<Map<String, Object>> getTreeMenu(int pid,List<Map<String, Object>> list) throws ExceptionHandler{
		String sql = "select * from sys.t_sys_menu where pid="+pid+" order by ordernum asc";
		List<Map<String, Object>> tem = DML.query(sql);
		if(tem!=null&&tem.size()>0)
			for(Map<String, Object> map: tem){
				map.put("DEPTH", map.get("IDPATH").toString().replaceAll("\\d", "").length()-1);
				list.add(map);
				getTreeMenu(Integer.parseInt(map.get("ID").toString()), list);
			}
		return list;
	}
	
	
	/**
	 * 将菜单载入缓存
	 * 
	 * @throws ExceptionHandler
	 */
	@SuppressWarnings("unchecked")
	public static void cache() throws ExceptionHandler {
		// 递归查询所有菜单数据
		//String sql = "SELECT t.id,t.pid,t.depth,m.idpath,m.kind,m.name,m.url,m.icon FROM connectby('sys.t_sys_menu', 'id', 'pid','ordernum','0',0,'/')AS t(id int,pid int,depth int,branch text,pos int) left join sys.t_sys_menu m on m.id=t.id where t.id > 0";
		//List<Map<String, Object>> list = DML.query(sql);

		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		getTreeMenu(0, list);
		
		// 清空菜单缓存
		CacheManager.getCache(Caches.menus.name(), true).clear();

		CacheManager.put(Caches.menus.toString(), "tree", new LinkedHashMap<String, SysMenu2>());// 以树形结构存储
		Map<String, SysMenu2> tree = (Map<String, SysMenu2>) CacheManager.get(Caches.menus.name(), "tree");
		CacheManager.put(Caches.menus.toString(), "list", new LinkedHashMap<String, SysMenu2>());// 以线性结构存储
		Map<String, SysMenu2> menus = (Map<String, SysMenu2>) CacheManager.get(Caches.menus.name(), "list");

		SysMenu2 menu = null;
		String idPath = null;
		SysMenu2 parent = null;
		List<SysMenu2> children = null;

		for (Map<String, Object> map : list) {
			menu = new SysMenu2();
			Reflect.map2Obj(map, menu);

			// Step 1.线性缓存所有菜单
			menus.put(String.valueOf(menu.getId()), menu);

			// Step 2.树形结构缓存所有菜单
			if (Integer.parseInt(map.get("DEPTH").toString()) > 1) {
				// 对于非顶层菜单(子菜单)，需要将其压入到其父菜单下，这里的重点是找到一个子菜单的直接父节点对象(考虑到菜单可以无限扩展层级，这里需要采用递归的方法)
				idPath = menu.getIdpath();
				idPath = idPath.substring(1, idPath.length() - 1);// 去除首尾的/
				idPath = idPath.substring(0, idPath.lastIndexOf("/"));// 只保留父节点IDPath
				parent = findParent(idPath);
				if (parent != null) {
					// menu.setParent(parent);
					children = parent.getChildren();
					if (children == null) {
						children = new ArrayList<SysMenu2>(10);
						parent.setChildren(children);
					}
					children.add(menu);
				}
			} else {
				// 压入顶层菜单
				tree.put(String.valueOf(menu.getId()), menu);
			}
		}
		list = null;

		children = null;
		parent = null;
		menu = null;

		menus = null;
		tree = null;

		// 测试
		// List<String> keys = (List<String>) CacheManager.getCacheKeys(Caches.menus.name());
		// for (String key : keys) {
		// Object obj = CacheManager.get(Caches.menus.name(), key);
		// if ("tree".equals(key)) {
		// System.out.println("----------------------------------tree------------------------------------------------");
		// } else {
		// System.out.println("----------------------------------list------------------------------------------------");
		// }
		// tree = (Map<String, SysMenu2>) obj;
		// Set<Entry<String, SysMenu2>> set = tree.entrySet();
		// Iterator<Entry<String, SysMenu2>> it = set.iterator();
		// while (it.hasNext()) {
		// Entry<String, SysMenu2> entry = it.next();
		// System.out.println(entry.getValue().getName());
		// }
		// it = null;
		// set = null;
		// tree = null;
		// }

	}

	/**
	 * 从缓存中查找菜单的直接根节点
	 * 
	 * @param idPath
	 *            菜单IDPath
	 * @return
	 * @throws ExceptionHandler
	 */
	@SuppressWarnings("unchecked")
	private static SysMenu2 findParent(String idPath) throws ExceptionHandler {
		/**
		 * 一个3级菜单的idpath： /1/2/3/，传递进来的的idpath已经去除了头尾的 /且只保留父节点id，如：1/2 父节点倒查 1/2/3/4/5 ，如果要找到节点5的父节点4，则需要按照如下的过程进行查找<br>
		 * 1/2/3/4 ，找到4，则必须找到3；找到4，返回<br>
		 * 1/2/3 找到3，则必须找到2；找到3，返回<br>
		 * 1/2 找到2，则必须找到1；找到2，返回<br>
		 * 1 找到1，返回
		 */
		SysMenu2 parent = null;
		String[] ids = idPath.split("/");
		if (ids.length > 1) {
			String parentIDPath = idPath.substring(0, idPath.lastIndexOf("/"));
			parent = findParent(parentIDPath);
			// 非顶层菜单，需要从菜单的children中查找
			if (parent != null) {
				int currentID = Integer.parseInt(idPath.substring(idPath.lastIndexOf("/") + 1));
				List<SysMenu2> children = parent.getChildren();
				if (children != null) {
					for (SysMenu2 menu : children) {
						if (menu.getId() == currentID) {
							parent = menu;
							break;
						}
					}
					children = null;
				}
			}
		} else {
			// 顶层菜单直接从缓存中获取
			Map<String, SysMenu2> tree = (Map<String, SysMenu2>) CacheManager.get(Caches.menus.name(), "tree");
			parent = tree.get(idPath);
			tree = null;
		}
		ids = null;
		return parent;
	}
}